Completed
Pull Request — master (#386)
by Sander
02:53
created

angular.controller(ꞌCredentialCtrlꞌ)   D

Complexity

Conditions 10
Paths 24

Size

Total Lines 390

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
c 1
b 0
f 0
nc 24
nop 19
dl 0
loc 390
rs 4.8196

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like angular.controller(ꞌCredentialCtrlꞌ) often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
/**
2
 * Nextcloud - passman
3
 *
4
 * @copyright Copyright (c) 2016, Sander Brand ([email protected])
5
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel ([email protected])
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
(function () {
24
	'use strict';
25
26
27
	/**
28
	 * @ngdoc function
29
	 * @name passmanApp.controller:MainCtrl
30
	 * @description
31
	 * # MainCtrl
32
	 * Controller of the passmanApp
33
	 */
34
	angular.module('passmanApp')
35
		.controller('CredentialCtrl', ['$scope', 'VaultService', 'SettingsService', '$location', 'CredentialService',
36
			'$rootScope', 'FileService', 'EncryptService', 'TagService', '$timeout', 'NotificationService', 'CacheService', 'ShareService', 'SharingACL', '$interval', '$filter', '$routeParams', '$sce', '$translate',
37
			function ($scope, VaultService, SettingsService, $location, CredentialService, $rootScope, FileService, EncryptService, TagService, $timeout, NotificationService, CacheService, ShareService, SharingACL, $interval, $filter, $routeParams, $sce, $translate) {
38
				$scope.active_vault = VaultService.getActiveVault();
39
				if (!SettingsService.getSetting('defaultVault') || !SettingsService.getSetting('defaultVaultPass')) {
40
					if (!$scope.active_vault) {
41
						$location.path('/');
42
					}
43
				} else {
44
					if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) {
45
						var _vault = angular.copy(SettingsService.getSetting('defaultVault'));
46
						_vault.vaultKey = angular.copy(SettingsService.getSetting('defaultVaultPass'));
47
						VaultService.setActiveVault(_vault);
48
						$scope.active_vault = _vault;
49
						//@TODO check if vault exists
50
					}
51
				}
52
53
				$scope.show_spinner = true;
54
				var fetchCredentials = function () {
55
					VaultService.getVault({guid: $routeParams.vault_id}).then(function (vault) {
56
						var vaultKey = angular.copy($scope.active_vault.vaultKey);
57
						var _credentials = angular.copy(vault.credentials);
58
						vault.credentials = [];
59
						$scope.active_vault = vault;
60
						$scope.active_vault.vaultKey = vaultKey;
61
						if(!$rootScope.vaultCache){
62
              $rootScope.vaultCache = [];
63
						}
64
						VaultService.setActiveVault($scope.active_vault);
65
						for (var i = 0; i < _credentials.length; i++) {
66
							var _credential = _credentials[i];
67
							try {
68
								if (!_credential.shared_key) {
69
									_credential = CredentialService.decryptCredential(angular.copy(_credential));
70
71
								} else {
72
									var enc_key = EncryptService.decryptString(_credential.shared_key);
73
									_credential = ShareService.decryptSharedCredential(angular.copy(_credential), enc_key);
74
								}
75
								_credential.tags_raw = _credential.tags;
76
							} catch (e) {
77
78
								NotificationService.showNotification($translate.instant('error.decrypt'), 5000);
79
								//$rootScope.$broadcast('logout');
80
								//SettingsService.setSetting('defaultVaultPass', null);
81
								//.setSetting('defaultVault', null);
82
								//$location.path('/')
83
84
							}
85
							_credentials[i] = _credential;
86
						}
87
88
						ShareService.getCredendialsSharedWithUs(vault.guid).then(function (shared_credentials) {
89
							for (var c = 0; c < shared_credentials.length; c++) {
90
								var _shared_credential = shared_credentials[c];
91
								var decrypted_key = EncryptService.decryptString(_shared_credential.shared_key);
92
								var _shared_credential_data;
93
								try {
94
									_shared_credential_data = ShareService.decryptSharedCredential(_shared_credential.credential_data, decrypted_key);
95
								} catch (e) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
96
97
								}
98
								if (_shared_credential_data) {
99
									delete _shared_credential.credential_data;
100
									_shared_credential_data.acl = _shared_credential;
101
									_shared_credential_data.acl.permissions = new SharingACL(_shared_credential_data.acl.permissions);
102
									_shared_credential_data.tags_raw = _shared_credential_data.tags;
103
									_credentials.push(_shared_credential_data);
104
								}
105
							}
106
							angular.merge($scope.active_vault.credentials, _credentials);
107
							$scope.show_spinner = false;
108
							$rootScope.$broadcast('credentials_loaded');
109
							$rootScope.vaultCache[$scope.active_vault.guid] = angular.copy($scope.active_vault);
110
							if(!vault.private_sharing_key){
111
								var key_size = 1024;
112
								ShareService.generateRSAKeys(key_size).then(function (kp) {
113
									var pem = ShareService.rsaKeyPairToPEM(kp);
114
									$scope.creating_keys = false;
115
									$scope.active_vault.private_sharing_key = pem.privateKey;
116
									$scope.active_vault.public_sharing_key = pem.publicKey;
117
									$scope.$digest();
118
									VaultService.updateSharingKeys($scope.active_vault);
119
								});
120
							}
121
						});
122
					});
123
				};
124
125
				var getPendingShareRequests = function () {
126
					ShareService.getPendingRequests().then(function (shareRequests) {
127
						if (shareRequests.length > 0) {
128
							$scope.incoming_share_requests = shareRequests;
129
							jQuery('.share_popup').dialog({
130
								width: 600,
131
								position: ['center', 90]
132
							});
133
						}
134
					});
135
				};
136
137
138
139
				var refresh_data_interval = null;
140
				if ($scope.active_vault) {
141
					$scope.$parent.selectedVault = true;
142
					if($rootScope.vaultCache && $rootScope.vaultCache[$scope.active_vault.guid]){
143
            $scope.active_vault = $rootScope.vaultCache[$scope.active_vault.guid];
144
            $rootScope.$broadcast('credentials_loaded');
145
            $scope.show_spinner = false;
146
          } else {
147
            fetchCredentials();
148
          }
149
					getPendingShareRequests();
150
					refresh_data_interval = $interval(function () {
151
						fetchCredentials();
152
						getPendingShareRequests();
153
					}, 60000 * 5);
154
				}
155
				
156
				$scope.$on('$destroy', function () {
157
					$interval.cancel(refresh_data_interval);
158
				});
159
160
161
				$scope.permissions = new SharingACL(0);
162
163
				$scope.hasPermission = function (acl, permission) {
164
					if (acl) {
165
						var tmp = new SharingACL(acl.permission);
166
						return tmp.hasPermission(permission);
167
					} else {
168
						return true;
169
					}
170
171
				};
172
173
				$scope.acceptShareRequest = function (share_request) {
174
					var crypted_shared_key = share_request.shared_key;
175
					var private_key = EncryptService.decryptString(VaultService.getActiveVault().private_sharing_key);
176
177
					private_key = ShareService.rsaPrivateKeyFromPEM(private_key);
178
					/** global: forge */
179
					crypted_shared_key = private_key.decrypt(forge.util.decode64(crypted_shared_key));
180
					crypted_shared_key = EncryptService.encryptString(crypted_shared_key);
181
182
					ShareService.saveSharingRequest(share_request, crypted_shared_key).then(function () {
183
						var idx = $scope.incoming_share_requests.indexOf(share_request);
184
						$scope.incoming_share_requests.splice(idx, 1);
185
						var active_share_requests = false;
186
						for (var v = 0; v < $scope.incoming_share_requests.length; v++) {
187
							if ($scope.incoming_share_requests[v].target_vault_id === $scope.active_vault.vault_id) {
188
								active_share_requests = true;
189
							}
190
						}
191
						if (active_share_requests === false) {
192
							jQuery('.ui-dialog').remove();
193
							fetchCredentials();
194
						}
195
					});
196
				};
197
198
				$scope.declineShareRequest = function (share_request) {
199
					ShareService.declineSharingRequest(share_request).then(function () {
200
						var idx = $scope.incoming_share_requests.indexOf(share_request);
201
						$scope.incoming_share_requests.splice(idx, 1);
202
						var active_share_requests = false;
203
						for (var v = 0; v < $scope.incoming_share_requests.length; v++) {
204
							if ($scope.incoming_share_requests[v].target_vault_id === $scope.active_vault.vault_id) {
205
								active_share_requests = true;
206
							}
207
						}
208
						if (active_share_requests === false) {
209
							jQuery('.ui-dialog').remove();
210
							fetchCredentials();
211
						}
212
					});
213
				};
214
215
216
217
				var settingsLoaded = function () {
218
					$scope.settings = SettingsService.getSettings();
219
				};
220
221
				if(!SettingsService.getSetting('settings_loaded')){
222
					$rootScope.$on('settings_loaded', function () {
223
						settingsLoaded();
224
					});
225
				} else {
226
					settingsLoaded();
227
				}
228
229
230
				$scope.addCredential = function () {
231
					var new_credential = CredentialService.newCredential();
232
					var enc_c = CredentialService.encryptCredential(new_credential);
233
					SettingsService.setSetting('edit_credential', enc_c);
234
					$location.path('/vault/' + $scope.active_vault.guid + '/new');
235
				};
236
237
				$scope.editCredential = function (credential) {
238
					var _credential = angular.copy(credential);
239
					$rootScope.$emit('app_menu', false);
240
					SettingsService.setSetting('edit_credential', CredentialService.encryptCredential(_credential));
241
					$location.path('/vault/' + $scope.active_vault.guid + '/edit/' + _credential.guid);
242
				};
243
244
				$scope.getRevisions = function (credential) {
245
					var _credential = angular.copy(credential);
246
					$rootScope.$emit('app_menu', false);
247
					SettingsService.setSetting('revision_credential', CredentialService.encryptCredential(_credential));
248
					$location.path('/vault/' + $scope.active_vault.guid + '/' + _credential.guid + '/revisions');
249
				};
250
251
				$scope.shareCredential = function (credential) {
252
					var _credential = angular.copy(credential);
253
					$rootScope.$emit('app_menu', false);
254
					SettingsService.setSetting('share_credential', CredentialService.encryptCredential(_credential));
255
					$location.path('/vault/' + $scope.active_vault.guid + '/' + _credential.guid + '/share');
256
				};
257
258
				var notification;
259
				$scope.deleteCredential = function (credential) {
260
					var _credential = angular.copy(credential);
261
					try {
262
						_credential = CredentialService.decryptCredential(_credential);
263
					} catch (e) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
264
265
					}
266
					_credential.delete_time = new Date().getTime() / 1000;
267
					for (var i = 0; i < $scope.active_vault.credentials.length; i++) {
268
						if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) {
269
							$scope.active_vault.credentials[i].delete_time = _credential.delete_time;
270
						}
271
					}
272
					$scope.closeSelected();
273
					if (notification) {
274
						NotificationService.hideNotification(notification);
275
					}
276
					var key = CredentialService.getSharedKeyFromCredential(_credential);
277
					CredentialService.updateCredential(_credential, false, key).then(function () {
278
						notification = NotificationService.showNotification($translate.instant('credential.deleted'), 5000);
279
					});
280
				};
281
282
				$scope.recoverCredential = function (credential) {
283
					var _credential = angular.copy(credential);
284
					try {
285
						_credential = CredentialService.decryptCredential(_credential);
286
					} catch (e) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
287
288
					}
289
					for (var i = 0; i < $scope.active_vault.credentials.length; i++) {
290
						if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) {
291
							$scope.active_vault.credentials[i].delete_time = 0;
292
						}
293
					}
294
					_credential.delete_time = 0;
295
					$scope.closeSelected();
296
					if (notification) {
297
						NotificationService.hideNotification(notification);
298
					}
299
					var key = CredentialService.getSharedKeyFromCredential(_credential);
300
					CredentialService.updateCredential(_credential, false, key).then(function () {
301
						NotificationService.showNotification($translate.instant('credential.recovered'), 5000);
302
					});
303
				};
304
305
				$scope.destroyCredential = function (credential) {
306
					var _credential = angular.copy(credential);
307
					CredentialService.destroyCredential(_credential.guid).then(function () {
308
						for (var i = 0; i < $scope.active_vault.credentials.length; i++) {
309
							if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) {
310
								$scope.active_vault.credentials.splice(i, 1);
311
								NotificationService.showNotification($translate.instant('credential.destroyed'), 5000);
312
								break;
313
							}
314
						}
315
					});
316
				};
317
318
				$scope.view_mode = 'list'; //@TODO make this a setting
319
				$scope.switchViewMode = function (viewMode) {
320
					$scope.view_mode = viewMode;
321
				};
322
323
				$scope.filterOptions = {
324
					filterText: '',
325
					fields: ['label', 'username', 'email', 'custom_fields']
326
				};
327
328
329
				$scope.filtered_credentials = [];
330
				$scope.$watch('[selectedtags, filterOptions, delete_time, active_vault.credentials]', function () {
331
					if (!$scope.active_vault) {
332
						return;
333
					}
334
					if ($scope.active_vault.credentials) {
335
						var credentials = angular.copy($scope.active_vault.credentials);
336
						var filtered_credentials = $filter('credentialSearch')(credentials, $scope.filterOptions);
337
						filtered_credentials = $filter('tagFilter')(filtered_credentials, $scope.selectedtags);
338
						filtered_credentials = $filter('filter')(filtered_credentials, {hidden: 0});
339
						$scope.filtered_credentials = filtered_credentials;
340
						$scope.filterOptions.selectedtags = angular.copy($scope.selectedtags);
341
						for (var i = 0; i < $scope.active_vault.credentials.length; i++) {
342
							var _credential = $scope.active_vault.credentials[i];
343
							if (_credential.tags) {
344
								TagService.addTags(_credential.tags);
345
							}
346
						}
347
					}
348
349
				}, true);
350
351
				$scope.selectedtags = [];
352
				var to;
353
				$rootScope.$on('selected_tags_updated', function (evt, _sTags) {
354
					var _selectedTags = [];
355
					for (var x = 0; x < _sTags.length; x++) {
356
						_selectedTags.push(_sTags[x].text);
357
					}
358
					$scope.selectedtags = _selectedTags;
359
					$timeout.cancel(to);
360
					if (_selectedTags.length > 0) {
361
						to = $timeout(function () {
362
							if ($scope.filtered_credentials) {
363
								var _filtered_tags = [];
364
								for (var i = 0; i < $scope.filtered_credentials.length; i++) {
365
									var tags = $scope.filtered_credentials[i].tags_raw;
366
									for (var x = 0; x < tags.length; x++) {
367
										var tag = tags[x].text;
368
										if (_filtered_tags.indexOf(tag) === -1) {
369
											_filtered_tags.push(tag);
370
										}
371
									}
372
								}
373
374
								$rootScope.$emit('limit_tags_in_list', _filtered_tags);
375
							}
376
						}, 50);
377
					}
378
				});
379
380
				$scope.delete_time = 0;
381
				$scope.showCredentialRow = function (credential) {
382
					if ($scope.delete_time === 0) {
383
						return credential.delete_time === 0;
384
					} else {
385
						return credential.delete_time > $scope.delete_time;
386
					}
387
388
				};
389
390
				$rootScope.$on('set_delete_time', function (event, time) {
391
					$scope.delete_time = time;
392
				});
393
394
				$scope.setDeleteTime = function (delete_time) {
395
					$scope.delete_time = delete_time;
396
				};
397
398
				$scope.selectedCredential = false;
399
				$scope.selectCredential = function (credential) {
400
					if(credential.description) {
401
						credential.description_html = $sce.trustAsHtml(angular.copy(credential.description).replace("\n", '<br />'));
402
					}
403
					$scope.selectedCredential = angular.copy(credential);
404
					$rootScope.$emit('app_menu', true);
405
				};
406
407
				$scope.closeSelected = function () {
408
					$rootScope.$emit('app_menu', false);
409
					$scope.selectedCredential = false;
410
				};
411
412
				$rootScope.$on('logout', function () {
413
					if($scope.active_vault) {
414
            $rootScope.vaultCache[$scope.active_vault.guid] = null;
415
          }
416
					$scope.active_vault = null;
417
					$scope.credentials = [];
418
//				$scope.$parent.selectedVault = false;
419
420
				});
421
422
				$scope.clearState = function () {
423
					$scope.delete_time = 0;
424
				};
425
426
			}]);
427
}());